﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

namespace GameFrameWork
{
    class ResModule : IResModule, IDisposable
    {

        class SingleRecord
        {
            public GameObject go;
            public string assetName;
            public void Destroy()
            {
                if (go != null)
                    GameObject.DestroyImmediate(go);
                go = null;
            }
        }

        // loading
        private Dictionary<string, LoadAssetAwaiter> m_Loader = new Dictionary<string, LoadAssetAwaiter>();
        private Dictionary<Transform, SingleRecord> m_Singles = new Dictionary<Transform, SingleRecord>();
        private Dictionary<Transform, IUILoadAssetResult> m_SingleLoading = new Dictionary<Transform, IUILoadAssetResult>();

        public async Task<GameObject> Load(string path)
        {
            if (string.IsNullOrEmpty(path))
                return null;
            if (!m_Loader.ContainsKey(path))
            {
                m_Loader.Add(path, new LoadAssetAwaiter(path));
            }
            var loader = m_Loader[path];
            var result = await loader;
            return result as GameObject;
        }

        public void Recycle(string path, GameObject prefab)
        {
            if (string.IsNullOrEmpty(path))
                return;
            if (m_Loader.TryGetValue(path, out var loader))
            {
                loader.Unload();
                m_Loader.Remove(path);
            }
        }

        public void Dispose()
        {
            foreach (var loader in m_Loader.Values)
            {
                loader.Unload();
            }
            m_Loader.Clear();
            foreach (var data in m_Singles.Values)
            {
                data.Destroy();
            }
            m_Singles.Clear();
            foreach (var loading in m_SingleLoading.Values)
            {
                loading.Cancel();
            }
            m_SingleLoading.Clear();
        }

        public IUILoadAssetResult LoadAsset(string assetName, Transform parent = null)
        {
            if (string.IsNullOrEmpty(assetName))
                return null;
            if (!m_Loader.ContainsKey(assetName))
            {
#pragma warning disable CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
                Load(assetName);
#pragma warning restore CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
            }
            var loader = m_Loader[assetName];
            IUILoadAssetResult result = new UILoadAssetResult(loader, parent);
            //Debug.Log($"[LoadAsset] ? imgID:{parent?.GetInstanceID()}, {result?.GetHashCode()}, {loader.IsCompleted}, {loader.IsUnload}, {loader.IsLoading}, {loader.Asset}");
            return result;
        }

        private void CleanSingle(Transform parent, string assetName = null)
        {
            if (m_Singles.TryGetValue(parent, out var old) && old.assetName != assetName)
            {
                old.Destroy();
                m_Singles.Remove(parent);
            }
        }

        public void AttachEffectSingleCancel(Transform parent, string assetName = null)
        {
            CleanSingle(parent, assetName);
            if (m_SingleLoading.TryGetValue(parent, out var oldLoading))
            {
                oldLoading.Cancel();
                m_SingleLoading.Remove(parent);
            }
        }

        public async Task<GameObject> AttachEffectSingle(Transform parent, string assetName)
        {
            AttachEffectSingleCancel(parent, assetName);
            if (m_Singles.TryGetValue(parent, out var old))
                return old.go;
            if (parent == null || !parent)
                return null;
            var loading = LoadAsset(assetName, parent);
            if (loading == null)
                return null;
            m_SingleLoading.Add(parent, loading);
            var go = await loading;
            if (parent == null || !parent || go == null || !go)
            {
                loading.Cancel();
                return null;
            }
            m_SingleLoading.Remove(parent);
            CleanSingle(parent);
            m_Singles.Add(parent, new SingleRecord() { go = go, assetName = assetName });
            return go;
        }
    }
}

